package com.zlsy.thread.singleton;

import java.util.Objects;

/**
 * @author zhouliang
 * @date 2020/5/8 20:39
 * <p>
 * 懒汉式-双重检查模式
 */
public class Singleton6 {

    //volatile
    private static volatile Singleton6 instance;

    private Singleton6() {
    }

    public static Singleton6 getInstance() {
        if (Objects.isNull(instance)) {//① 判断引用是否为空
            synchronized (Singleton6.class) {
                if (Objects.isNull(instance)) {
                    //类的创建分为三步：1、新建一个空对象 2、调用构造方法 3、赋值给引用
                    //但是由于cpu是会重排序的。
                    //所以上面的步骤完全可以是这样的：1、3、2
                    //所以如果发生了cpu指令重排，
                    // 当线程2进入①的时候，由于线程1已经完成了赋值，调度器暂停线程1，切换给线程2执行，这个时候对象就不是为空了
                    //那么线程2就直接跳过synchronized返回出去这个未初始化好的对象
                    //这样就导致了这个对象不是线程安全的。
                    //我们之前已经知道volatile可以禁止重排序，所以我们在这个对象前面加个volatile
                    instance = new Singleton6();    //②：赋值给引用
                }
            }
        }
        return instance;
    }
}
